package xyz.xtt.schedule.support;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import xyz.xtt.schedule.dto.TblLuckPhonePoolDTO;

import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 国美靓号市场api服务
 *
 * @author dale
 * @since 2024/12/31
 **/
@Component
@RefreshScope
@Slf4j
public class GomeLuckPhoneHttpService {
    @Value("${gome.luck.phone.channel.account}")
    private String channelAccount;
    @Value("${gome.luck.phone.channel.secret}")
    private String channelSecret;
    @Value("${gome.luck.phone.url}")
    private String fetchUrl;

    /**
     * 获取靓号列表
     * @param pageNo
     * @param pageSize
     * @return
     */
    public List<TblLuckPhonePoolDTO> fetchPhoneList(int pageNo, int pageSize) {
        // 构造请求参数
        String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        Map<String, String> parameters = Map.of(
                "channelAccount", channelAccount,
                "timeStamp", timeStamp,
                "sign", generateSign(timeStamp),
                "page", pageNo + "",
                "limit", pageSize + ""
        );

        String formData = buildFormData(parameters);

        // 创建 HttpClient
        HttpClient client = HttpClient.newHttpClient();

        // 构造 POST 请求
        String url = fetchUrl + "/queryPhone";
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .header("Accept", "application/json; charset=utf-8")
                .POST(HttpRequest.BodyPublishers.ofString(formData))
                .build();

        // 发送请求并获取响应
        int maxTries = 4;
        while (maxTries-- > 0) {
            try {
                log.info("fetchPhoneList Sending request to url:{} with params:{}", url, formData);
                HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
                String body = decodeUnicode(response.body());
                JSONObject bodyObj = JSONUtil.parseObj(body);
                if (response.statusCode() == 200 && bodyObj.getInt("code") == 0) {
                    return bodyObj.getBeanList("data", TblLuckPhonePoolDTO.class);
                } else {
                    log.error("fetchPhoneList error statusCode:{} body:{}", body);
                }
            } catch (Exception e) {
                log.error("fetchPhoneList error:{}", e.getMessage());
            }
        }
        throw new RuntimeException("fetchPhoneList error");
    }

    /**
     * 获取靓号列表总条数
     * @return
     */
    public Long fetchPhoneCount() {
        // 构造请求参数
        String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        Map<String, String> parameters = Map.of(
                "channelAccount", channelAccount,
                "timeStamp", timeStamp,
                "sign", generateSign(timeStamp),
                "page", "1",
                "limit", "1"
        );

        String formData = buildFormData(parameters);

        // 创建 HttpClient
        HttpClient client = HttpClient.newHttpClient();

        // 构造 POST 请求
        String url = fetchUrl + "/queryPhone";
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .header("Accept", "application/json; charset=utf-8")
                .POST(HttpRequest.BodyPublishers.ofString(formData))
                .build();

        // 发送请求并获取响应
        int maxTries = 4;
        while (maxTries-- > 0) {
            try {
                log.info("fetchPhoneCount Sending request to url:{} with params:{}", url, formData);
                HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
                String body = decodeUnicode(response.body());
                JSONObject bodyObj = JSONUtil.parseObj(body);
                if (response.statusCode() == 200 && bodyObj.getInt("code") == 0) {
                    return bodyObj.getLong("count");
                } else {
                    log.error("fetchPhoneCount error statusCode:{} body:{}", body);
                }
            } catch (Exception e) {
                log.error("fetchPhoneCount error:{}", e.getMessage());
            }
        }
        throw new RuntimeException("fetchPhoneCount error");
    }

    /**
     * 获取订单状态
     * @param orderNo
     * @return
     */
    public Integer fetchOrderStatus(Long orderNo) {
        // 构造请求参数
        String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        Map<String, String> parameters = Map.of(
                "channelAccount", channelAccount,
                "timeStamp", timeStamp,
                "sign", generateSign(timeStamp),
                "orderNo", orderNo + ""
        );

        String formData = buildFormData(parameters);

        // 创建 HttpClient
        HttpClient client = HttpClient.newHttpClient();

        // 构造 POST 请求
        String url = fetchUrl + "/queryOrder";
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .header("Accept", "application/json; charset=utf-8")
                .POST(HttpRequest.BodyPublishers.ofString(formData))
                .build();

        // 发送请求并获取响应
        int maxTries = 4;
        while (maxTries-- > 0) {
            try {
                log.info("fetchOrderStatus Sending request to url:{} with params:{}", url, formData);
                HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
                String body = decodeUnicode(response.body());
                JSONObject bodyObj = JSONUtil.parseObj(body);
                if (response.statusCode() == 200 && Objects.equals(bodyObj.getStr("state"),"0000")) {
                    return Integer.valueOf(bodyObj.getJSONObject("data").getStr("status"));
                } else {
                    log.error("fetchOrderStatus error statusCode:{} body:{}",response.statusCode(), body);
                }
            } catch (Exception e) {
                log.error("fetchOrderStatus error:{}", e.getMessage());
            }
        }
        return null;
    }

    /**
     * 生成签名
     *
     * @param timeStamp
     * @return
     */
    private String generateSign(String timeStamp) {
        return SecureUtil.md5(channelAccount + channelSecret + timeStamp).toLowerCase();
    }

    /**
     * 将参数 Map 转换为 application/x-www-form-urlencoded 格式
     *
     * @param data
     * @return
     */
    private static String buildFormData(Map<String, String> data) {
        return data.entrySet().stream()
                .map(entry -> URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) + "="
                        + URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))
                .collect(Collectors.joining("&"));
    }

    /**
     * 解码 Unicode 编码的字符串
     *
     * @param encoded
     * @return
     */
    private static String decodeUnicode(String encoded) {
        StringBuilder decoded = new StringBuilder();
        int i = 0;
        while (i < encoded.length()) {
            char c = encoded.charAt(i++);
            if (c == '\\' && i < encoded.length() && encoded.charAt(i) == 'u') {
                int codePoint = Integer.parseInt(encoded.substring(i + 1, i + 5), 16);
                decoded.append((char) codePoint);
                i += 5;
            } else {
                decoded.append(c);
            }
        }
        return decoded.toString();
    }
}
